package com.njwt.cloud.msconsumer.service;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCollapser;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import com.netflix.hystrix.contrib.javanica.conf.HystrixPropertiesManager;
import com.njwt.cloud.mscommon.pojo.OrderModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Future;

/**
 * @author <a href="mailto:xingxiao@gtmap.cn">xingxiaofeng</a>
 * @version2.1 2022-04-24
 * @description
 */
@Service
public class VipServiceImpl implements OrderHystrixService {
    @Autowired
    private RestTemplate restTemplate;
    // Hystrix请求合并,设置请求合并相关参数
    @HystrixCollapser
            (
                    //batchMethod 指定合并请求的方法,只能接受一个参数
                    batchMethod = "loadVipOrdersService",
                    //请求合并方式(requeset|global)
                    scope = com.netflix.hystrix.HystrixCollapser.Scope.GLOBAL,
                    collapserProperties = {
                            //请求时间间隔在20ms之内的请求会被合并为一个请求,默认为10ms
                            @HystrixProperty(name = "timerDelayInMilliseconds", value = "20"),
                            //设置触发批处理执行之前，在批处理中允许的最大请求数。
                            @HystrixProperty(name = "maxRequestsInBatch", value = "200")}
            )
    public Future<OrderModel> loaddFutureOrders(Integer id) {
        System.out.println("------------" + id);
        return null;
    }
    @HystrixCommand
    @Override
    public List<OrderModel> loadVipOrdersService(List<Integer> ids) {
        // TODO Auto-generated method stub
        Integer[] its = new Integer[] {};
        Integer[] id = ids.toArray(its);
        System.out.println("==================" + Arrays.toString(id));

        //将请求的参数进行处理，格式为ids=1&ids=2&ids=3
        String paramIds = Arrays.toString(id);
        paramIds = paramIds.replace("[", "ids=");
        paramIds = paramIds.replace("]", "");
        paramIds = paramIds.replace(", ", "&ids=");

        System.out.println(paramIds);
        // 通过制定需要调用的远程服务的名字获得服务实例对象
        String url = "http://orders-provider/order/orders?" + paramIds;
        System.out.println("==============" + url);
        // 调用远程的服务
        OrderModel[] orders = restTemplate.getForObject(url.toString(), OrderModel[].class);
        return Arrays.asList(orders);

    }


    @HystrixCommand(fallbackMethod = "fallBack01", commandProperties = {
            // 默认20个;10s内请求数大于10个时启动熔断，如果错误率没有50%不会触发fallBack01()。
            @HystrixProperty(
                    name = HystrixPropertiesManager.CIRCUIT_BREAKER_REQUEST_VOLUME_THRESHOLD,
                    value = "10"),
            // 请求错误率大于50%时就熔断，然后for循环发起请求，当请求符合熔断条件时将触发fallBack01()。
            @HystrixProperty(
                    name = HystrixPropertiesManager.CIRCUIT_BREAKER_ERROR_THRESHOLD_PERCENTAGE,
                    value = "50"),
            // 默认5秒;熔断多少秒后去尝试请求
            @HystrixProperty(
                    name = HystrixPropertiesManager.CIRCUIT_BREAKER_SLEEP_WINDOW_IN_MILLISECONDS,
                    value = "5000")
    }
    )
    @Override
    public OrderModel loadOrdersService(Integer id) {
        //注意：url中指定的是远程服务的名著中
        String url="http://orders-provider/order/orders/"+id;
        System.out.println("url=====--------===="+url.toString());
        if(id==1) {
            throw new RuntimeException();
        }
        if(id==2) {
            throw new RuntimeException();
        }

        //调用远程的服务
        OrderModel orders = restTemplate.getForObject(url.toString(), OrderModel.class);
        return orders;
    }

    /**
     * 线程池的使用
     * @param id
     * @return
     */
    @HystrixCommand
            (
                    //给provider提供的服务进行线程池分组,如果groupKey一样，运行在同一个线程池
                    groupKey = "orders-provider",
                    //指定需要调用的provider接口的方法名字
                    commandKey = "loadOrdersThreadService",
                    //给线程池起名字
                    threadPoolKey = "orders-provider",
                    threadPoolProperties = {
                            //线程池大小
                            @HystrixProperty(name = "coreSize", value = "30"),
                            //最大队列长度,正数表示阻塞队列
                            @HystrixProperty(name = "maxQueueSize",value = "100"),
                            //线程存活时间
                            @HystrixProperty(name = "keepAliveTimeMinutes", value = "2"),
                            //拒绝请求
                            @HystrixProperty(name = "queueSizeRejectionThreshold", value = "15")
                    },
                    //熔断回调方法
                    fallbackMethod = "fallBack01"
            )
    @Override
    public OrderModel loadOrdersThreadService(Integer id) {
        //注意：url中指定的是远程服务的名著中
        String url="http://orders-provider/order/orders/"+id;
        System.out.println("loadOrdersThreadService----"
                +Thread.currentThread().getName());
        //调用远程的服务
        OrderModel orders = restTemplate.getForObject(url.toString(), OrderModel.class);
        return orders;
    }

    /**
     * 信号隔离
     * @param id
     * @return
     */
    //fallbackMethod当前请求数在一个窗口期内容达到阈值，会调用fallBack01
    @HystrixCommand(fallbackMethod = "fallBack01", commandProperties = {
            @HystrixProperty(
                    name = HystrixPropertiesManager.EXECUTION_ISOLATION_STRATEGY,
                    value = "SEMAPHORE"), // SEMAPHORE表示信号量隔离
            @HystrixProperty(                  //executionIsolationSemaphoreMaxConcurrentRequests
                    name = HystrixPropertiesManager.EXECUTION_ISOLATION_SEMAPHORE_MAX_CONCURRENT_REQUESTS,
                    value = "5")// 信号量最大限度，当请求达到或超过该设置值后，其其余就会被拒绝。默认值是10。
    })
    @Override
    public OrderModel loadOrdersSignalService(Integer id) {
        //注意：url中指定的是远程服务的名著中
        String url="http://orders-provider/order/orders/"+id;
        //调用远程的服务
        OrderModel orders = restTemplate.getForObject(url.toString(), OrderModel.class);
        return orders;
    }


    /***
     * 实现熔断调用的托底方法
     */
    public OrderModel fallBack01(Integer id) {
        System.out.println("fallBack01============="+id);
        OrderModel orders=new OrderModel();
        orders.setId(-8888);
        orders.setRemark("服务器繁忙，请稍后再试......");
        return orders;

    }


}
